package cache

import "container/list"

type fifo struct {
	// 缓存最大容量，单位字节，这里值最大存放的 元素 的容量，key不算
	maxBytes int

	// 已使用的字节数，只包括value， key不算
	usedBytes int

	// 双链表
	ll *list.List
	// map的key是字符串，value是双链表中对应节点的指针
	cache map[string]*list.Element
}

// 创建一个新 Cache，如果 maxBytes 是0，则表示没有容量限制
func NewFifoCache(maxBytes int) Cache {
	return &fifo{
		maxBytes: maxBytes,
		ll:       list.New(),
		cache:    make(map[string]*list.Element),
	}
}

// 通过 Set 方法往 Cache 头部增加一个元素（如果已经存在，则移到头部，并修改值）
func (f *fifo) Set(key string, value interface{}) {
	if element, ok := f.cache[key]; ok {
		f.ll.MoveToFront(element)
		eVal := element.Value.(*entry)
		f.usedBytes = f.usedBytes - CalcLen(eVal.value) + CalcLen(value) // 更新占用内存大小
		element.Value = value
	} else {
		element := &entry{
			key:   key,
			value: value,
		}

		e := f.ll.PushFront(element) // 头部插入一个元素并返回该元素
		f.cache[key] = e

		f.usedBytes += element.Len()
	}

	// 如果超出内存长度，则删除队首的节点. 0表示无内存限制
	for f.maxBytes > 0 && f.maxBytes < f.usedBytes {
		f.DelOldest()
	}
}

// 获取指定元素
func (f *fifo) Get(key string) interface{} {
	if e, ok := f.cache[key]; ok {
		return e.Value.(*entry).value
	}

	return nil
}

// 删除指定元素
func (f *fifo) Del(key string) {
	if e, ok := f.cache[key]; ok {
		f.removeElement(e)
	}
}

// 删除最 '无用' 元素
func (f *fifo) DelOldest() {
	f.removeElement(f.ll.Back())
}

// 删除元素并更新内存占用大小
func (f *fifo) removeElement(e *list.Element) {
	if e == nil {
		return
	}

	f.ll.Remove(e)
	en := e.Value.(*entry)
	f.usedBytes -= en.Len()
	delete(f.cache, en.key)
}

// 链表长度
func (f *fifo) Len() int {
	return f.ll.Len()
}

// 缓存池占用内存大小
func (f *fifo) UseBytes() int {
	return f.usedBytes
}
